<?php
// +-------------------------------------------------------------------------------
// | DingZone [ A Rapid Development Framework For Dingtalk ]
// +-------------------------------------------------------------------------------
// | 企业用户相关Controller v1.0
// |
// | Copyright (c) 2014-2018 http://www.heimalanshi.com All rights reserved.
// | Author : Jie
// | Date : 2018-08-09
// +-------------------------------------------------------------------------------

namespace app\core\controller\enterprise;

use app\core\model\Enterprise;
use app\core\model\EnterpriseDept;
use app\core\model\EnterpriseModule;
use app\core\model\EnterpriseUser;
use app\core\model\SiteModule;
use common\Encryption;
use common\Random;
use common\XXTEAEncryption;
use ding\ApiHelper;
use think\exception\HttpResponseException;
use think\Session;

class UserController extends EnterpriseBaseController {

    protected function _checkLogin() {
        switch (strtolower($this->request->action())) {
            case "login":
            case "usernamelogin":
            case "mobilelogin":
            case "resetpassword":
            case "mobileresetpassword":
            case "dingscanauth":
            case "dingcodeauth":
            case "dingadminauth":
                return "";
            default:
                return parent::_checkLogin();
        }
    }


    /**
     * 检查登录
     */
    protected function _loginRestore() {
        if ($this->_isLogin()) {
            $url = Session::get('redirect_url_enterprise');
            Session::delete('redirect_url_enterprise');
            $eidInUrl = $this->_getEidFromUrl($url);
            if (empty($url) || in_array($url, ['/core/enterprise/login', '/core/enterprise/logout']) || ($eidInUrl && $this->eid != $eidInUrl)) {
                //跳转到首页
                $url = '/core/enterprise';
            }
            if (is_submit()) {
                $this->success("登录成功", $url);
            }
            throw new HttpResponseException(
                redirect($url)
            );
        }
    }

    /**
     * 获取url中的eid参数
     *
     * @param $url
     * @return string
     */
    protected function _getEidFromUrl($url) {
        $urlInfo = parse_url($url);
        $queryString = fetch($urlInfo, "query");
        $queryParams = explode("&", $queryString);
        foreach ($queryParams as $queryParam) {
            $queryParamNameValue = explode("=", $queryParam);
            $queryParamName = count($queryParamNameValue) > 0 ? $queryParamNameValue[0] : "";
            $queryParamValue = count($queryParamNameValue) > 1 ? $queryParamNameValue[1] : "";
            if (strtolower($queryParamName) == 'eid') {
                return $queryParamValue;
            }
        }
        return "";
    }

    /**
     * 登录页面
     *
     * @return \think\response\View
     * @throws \think\exception\DbException
     */
    public function login() {
        $this->_loginRestore();

        $eid = input("get.eid");
        if (empty($eid)) {
            $this->error("参数错误");
        }
        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }

        if (!input("?get.scan") && ($this->env['dingMobile'] || $this->env['dingPc'])) {
            // 钉钉手机环境或者钉钉PC环境，自动登录
            $this->_initJsapiConfig($enterprise, null);
            $this->assign("eid", $eid);
            return view("ding_auto_login");
        }
        $loginType = Enterprise::parseLoginType($enterprise);
        $this->assign("enterprise", $enterprise);
        $this->assign("loginType", $loginType);

        if ($this->env['mobile']) {
            return view("h5_login");
        } else {
            // 钉钉扫描登录
            $apiHelper = new ApiHelper($enterprise, null);
            $appid = $apiHelper->getAppid();

            $state = \session(SESSION_CORE_DING_SCAN_STATE);
            if (!$state) {
                $state = Random::get();
                \session(SESSION_CORE_DING_SCAN_STATE, $state);
            }
            $this->_log("call " . $state, 'error');
            $redirect_uri = $this->request->domain() . "/core/enterprise.user/dingScanAuth?eid=" . $eid;
            $redirect_uri = urlencode($redirect_uri);

            $url = "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=$appid&response_type=code&scope=snsapi_login&state=$state&redirect_uri=$redirect_uri";
            $this->assign("dingUrl", $url);
            return view();
        }
    }

    /**
     * 用户名密码登录
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function usernameLogin() {
        $this->_loginRestore();

        $eid = input("get.eid");
        if (empty($eid)) {
            $this->error("参数错误");
        }
        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }

        $username = input('post.username');
        $password = input('post.password');
        $this->_checkCaptcha();

        $user = EnterpriseUser::login($username, $password, $eid);
        if (!$user) {
            $this->error("登录失败");
        }
        $user['enterprise'] = $enterprise;
        $this->_setUserSession($user);
        $this->_loginRestore();
    }

    /**
     * 手机号登录
     *
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function mobileLogin() {
        $this->_loginRestore();

        $eid = input("get.eid");
        if (empty($eid)) {
            $this->error("参数错误");
        }
        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }

        $mobile = input('post.mobile');
        $smsCode = input('post.smscode');
        $password = input('post.password');

        if (!empty($smsCode)) {
            //检查短信验证码
            $smsHelper = $this->_getSmsHelper();
            $response = $smsHelper->checkVerify($mobile, $smsCode);
            if ($response['status'] != 1) {
                $this->error("登录失败：" . $response['info']);
            }

            $user = EnterpriseUser::getByMobile($mobile, $eid);
            if (!empty($user)) {
                EnterpriseUser::updateLoginInfo($user['id'], $eid);
            }
        } else {
            $user = EnterpriseUser::loginByMobile($mobile, $password, $eid);
        }
        if (!$user) {
            $this->error("登录失败");
        }
        $user['enterprise'] = $enterprise;
        $this->_setUserSession($user);
        $this->_loginRestore();
    }

    /**
     * 重置密码
     *
     * @return \think\response\View
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function resetPassword() {
        $eid = input("get.eid");
        if (empty($eid)) {
            $this->error("参数错误");
        }
        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }

        $loginType = Enterprise::parseLoginType($enterprise);
        $this->assign("enterprise", $enterprise);
        $this->assign("loginType", $loginType);

        if ($this->env['mobile']) {
            if ($this->user) {
                $this->assign("userPhone", EnterpriseUser::decodeMobile($this->user['mobile']));
            }
            return view("h5_reset_password");
        } else {
            return view();
        }
    }

    /**
     * 通过手机号重置密码
     *
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function mobileResetPassword() {
        $eid = input("get.eid");
        if (empty($eid)) {
            $this->error("参数错误");
        }
        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }

        $mobile = input('post.mobile');
        $smsCode = input('post.smscode');
        $password = input('post.password');

        //检查短信验证码
        $smsHelper = $this->_getSmsHelper();
        $response = $smsHelper->checkVerify($mobile, $smsCode);
        if ($response['status'] != 1) {
            $this->error("验证码验证失败：" . $response['info']);
        }

        $user = EnterpriseUser::getByMobile($mobile, $eid);
        if (empty($user)) {
            $this->error("未找到用户");
        }

        EnterpriseUser::updatePassword($eid, $user['id'], $password);
        $this->success("密码重置成功");
    }

    /**
     * 初始化jsapi
     *
     * @param $enterprise
     * @param $module
     * @return array
     * @throws \think\exception\DbException
     */
    private function _initJsapiConfig($enterprise, $module) {
        $apiHelper = new ApiHelper($enterprise, $module);

        $jsApiList = [
            'runtime.info',
            'biz.ding.post',
        ];
        $config = $apiHelper->getJsapiConfig($this->request->url(true));
        $config['jsApiList'] = $jsApiList;
        $this->assign("jsapiConfig", $config);
        $this->assign("jsapiConfigJson", json_encode($config));
        $this->assign("corpid", $apiHelper->getCorpid());
        return $config;
    }

    /**
     * 根据code验证登录
     *
     * @throws \think\exception\DbException
     */
    public function dingCodeAuth() {
        $eid = input("get.eid");
        if (empty($eid)) {
            $this->error("参数错误");
        }
        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }
        $apiHelper = new ApiHelper($enterprise, null);
        //根据code获取用户userid
        $code = input("get.code");
        $userinfo = $apiHelper->userGetuserinfo($code);
        if ($userinfo['errcode'] != 0) {
            $this->error("用户信息获取失败：" . $apiHelper->getLastStatusMsg());
        }
        $userid = $userinfo['userid'];
        // 获取用户信息
        $dingUser = $apiHelper->userGet($userid);
        if (empty($dingUser)) {
            $this->error("用户鉴权失败：" . $apiHelper->getLastStatusMsg());
        }
        // 同步用户信息
        $user = EnterpriseUser::syncDing($dingUser, $eid);
        EnterpriseUser::updateLoginInfo($user['id'], $eid);
        $user = EnterpriseUser::getById($eid, $user['id']);
        $user['enterprise'] = $enterprise;
        $this->_setUserSession($user);
        $this->_loginRestore();
    }

    /**
     * 钉钉扫码登录回调
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function dingScanAuth() {
        $eid = input("get.eid");
        $state = input("get.state");
        $code = input("get.code");

        $enterprise = Enterprise::get($eid);
        if (empty($enterprise)) {
            $this->error("参数错误");
        }

        $apiHelper = new ApiHelper($enterprise, null);

        $sessionState = \session(SESSION_CORE_DING_SCAN_STATE);
        \session(SESSION_CORE_DING_SCAN_STATE, null);
        if ($sessionState != $state) {
            $this->_log("钉钉扫码登录失败。state: " . $state . ", sessionSate: " . $sessionState, 'error');
            $this->error("非法state参数：" . $state);
        }

        // 根据临时授权码，获取用户授权的持久授权码
        $persistentCodeInfo = $apiHelper->snsGetPersistentCode($code);
        if (empty($persistentCodeInfo) || $persistentCodeInfo['errcode'] != 0) {
            $this->error("用户鉴权失败：" . $apiHelper->getLastStatusMsg());
        }
        // 根据持久授权码，获取用户授权的SNS_TOKEN
        $snsToken = $apiHelper->snsGetSnsToken($persistentCodeInfo['openid'], $persistentCodeInfo['persistent_code']);
        if (empty($snsToken)) {
            $this->error("用户鉴权失败：" . $apiHelper->getLastStatusMsg());
        }
        // 根据SNS_TOKEN，获取用户授权的个人信息
        $snsUserInfo = $apiHelper->snsGetuserinfo($snsToken);
        if (empty($snsUserInfo)) {
            $this->error("用户鉴权失败：" . $apiHelper->getLastStatusMsg());
        }
        // 根据unionid获取userid
        $userid = $apiHelper->userGetUseridByUnionid($snsUserInfo['unionid']);
        if (empty($userid)) {
            $this->error("用户鉴权失败：" . $apiHelper->getLastStatusMsg());
        }
        // 获取用户信息
        $dingUser = $apiHelper->userGet($userid);
        if (empty($dingUser)) {
            $this->error("用户鉴权失败：" . $apiHelper->getLastStatusMsg());
        }
        // 同步用户信息
        $user = EnterpriseUser::syncDing($dingUser, $eid);
        EnterpriseUser::updateLoginInfo($user['id'], $eid);
        $user = EnterpriseUser::getById($eid, $user['id']);
        $user['enterprise'] = $enterprise;
        $this->_setUserSession($user);
        $this->_loginRestore();
    }

    /**
     * 钉钉OA后台自动登录
     */
    public function dingAdminAuth() {
        $eid = input("get.eid");
        $code = input("get.code");

        return redirect("/core/enterprise?eid=" . $eid);
    }

    /**
     * 退出登录
     */
    public function logout() {
        $this->_clearUserSession();
        return redirect(fetch($_SERVER, 'HTTP_REFERER', '/core/enterprise/login?eid=' . $this->eid));
    }

    /**
     * 用户信息
     *
     * @return \think\response\View
     * @throws \think\exception\DbException
     */
    public function profile() {
        if (is_submit()) {
            $avatar = input("post.avatar");
            $password = input("post.password");
            $newPassword = input("post.newPassword");
            $newPassword2 = input("post.newPassword2");

            $where = ['id' => $this->userid, 'enterprise_id' => $this->eid];
            $data = [];
            //修改密码
            if (!empty($newPassword)) {
                if (empty($password)) {
                    $this->error("请输入现有登录密码");
                }
                if ($newPassword != $newPassword2) {
                    $this->error("两次输入的密码不同");
                }
                if (strlen($newPassword) < 5) {
                    $this->error("密码长度过短");
                }
                $ret = EnterpriseUser::checkPassword($this->userid, $password, $this->eid);
                if (!$ret) {
                    $this->error("当前密码输入错误");
                }

                $data['password'] = EnterpriseUser::generatePassword($newPassword);
            }
            // 头像
            if (!empty($avatar)) {
                $data['avatar'] = $avatar;
            }

            if (empty($data)) {
                $this->error("无内容更新");
            }

            EnterpriseUser::update($data, $where);
            if (isset($data['password'])) {
                // 本次更新了密码，退出重新更新
                $this->_clearUserSession();
                $this->success("更新成功，请重新登录");
            } else {
                // 更新session
                $this->user['avatar'] = $avatar;
                $this->_setUserSession($this->user);
                $this->success("更新成功");
            }
        }
        return view();
    }

    /**
     * 部门列表
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function departmentList() {
        $parentDepartmentId = input("post.parentDepartmentId", EnterpriseDept::ROOT_DEPT_ID);
        if ($this->enterprise['appid']) {
            $apiHelper = new ApiHelper($this->enterprise, null);
            $dingSubDepts = $apiHelper->departmentList($parentDepartmentId, false);
            $subDepts = [];
            foreach ($dingSubDepts as $dept) {
                $subDepts[] = [
                    'id' => $dept['id'],
                    'title' => $dept['name']
                ];
            }
        } else {
            $subDepts = EnterpriseDept::getSubDepts($this->eid, $parentDepartmentId);
        }
        $this->success("ok", null, $subDepts);
    }

    /**
     * 获取用户列表
     *
     * @throws \think\exception\DbException
     */
    public function userSimplelist() {
        $departmentId = input("post.departmentId");
        $offset = input("post.offset", 0);
        $size = input("post.size", 20);
        if ($this->enterprise['appid']) {
            $apiHelper = new ApiHelper($this->enterprise, null);
            $dingUsersResponse = $apiHelper->userSimplelist($departmentId, $offset, $size);
            $usersResponse = [
                'hasMore' => $dingUsersResponse['hasMore'],
                'userlist' => []
            ];
            foreach ($dingUsersResponse['userlist'] as $user) {
                $usersResponse['userlist'][] = [
                    'id' => $user['userid'],
                    'showname' => $user['name']
                ];
            }
        } else {
            $usersResponse = EnterpriseUser::selectByDept($this->eid, $departmentId, $offset, $size);
            foreach ($usersResponse['userlist'] as &$user) {
                unset($user['password']);
                unset($user['mobile']);
            }
        }

        $this->success("ok", null, $usersResponse);
    }

    /**
     * 角色列表
     *
     * @throws \think\exception\DbException
     */
    public function corpRoleList() {
        $offset = input("post.offset", 0);
        $size = input("post.size", 20);
        if ($this->enterprise['appid']) {
            $apiHelper = new ApiHelper($this->enterprise, null);
            $dingRolesResponse = $apiHelper->corpRoleList($size, $offset);
            $rolesResponse = [
                'hasMore' => $dingRolesResponse['has_more'],
                'list' => $dingRolesResponse['list']
            ];
        } else {
            //TODO
            $rolesResponse = [];
        }

        $this->success("ok", null, $rolesResponse);
    }
}
